#include "mystring.h"
#include <cstring>

namespace real
{
    // const size_t string::npos = -1;

    void string::reserve(size_t size)
    {
        if(size > _capacity)
        {
            char* newstr = new char[_capacity+1];
            strcpy(newstr, _str);
            delete [] _str;
            _str = newstr;
            _capacity = size;
        }
    }

    void string::push_back(char c)
    {
        if(_size == _capacity)
        {
            reserve(_capacity==0?4:_capacity*2);
        }
        _str[_size++] = c;
        _str[_size] = '\0';
    }

    void string::append(const char* str)
    {
        size_t l = strlen(str);
        if(l+_size > _capacity)
        {
            size_t new_capcity = l+_size > _capacity*2?(l+_size):_capacity*2 ;
            reserve(new_capcity);
        }
        // memcpy(_str+_size, str, l+1);
        strcpy(_str+_size, str);
        _size += l;
    }

    string& string::insert(size_t pos, const char c)
    {
        assert(pos<=_size);
        if(_size == _capacity)
        {
            reserve(_capacity==0?4:_capacity*2);
        }
        // for (long i=(long)_size; i>=(long)pos; --i) {
        //     _str[i+1] = _str[i];
        // }
        size_t end = _size+1;
        while(end>pos)
        {
            _str[end] = _str[end-1];
            --end;
        }
        _str[pos] = c;
        ++_size;
        return *this;
    }

    string& string::insert(size_t pos, const char* str)
    {
        assert(pos<=_size);
        size_t l = strlen(str);
        if(l+_size > _capacity)
        {
            size_t new_capcity = l+_size > _capacity*2?(l+_size):_capacity*2 ;
            reserve(new_capcity);
        }
        // for (long i=(long)_size; i>=(long)pos; --i) {
        //     _str[i+(long)l] = _str[i];
        // }
        size_t end = _size+l;
        while(end>(pos+l-1))
        {
            _str[end] = _str[end-l];
            --end;
        }
        memcpy(_str+pos, str, l);
        _size += l;
        return *this;
    }

    string& string::erase(size_t pos, size_t len)
    {
        assert(pos<_size);
        // len = len>(_size-pos)?_size-pos-1:len;
        // while(pos<_size)
        // {
        //     _str[pos] = _str[pos+len];
        //     ++pos;
        // }
        // _size -= len ;
        if(len >= (_size-pos) )
        {
            _str[pos] = '\0';
            _size = pos;
        }
        else 
        {
            size_t i = pos;
            while( i <= _size-len) // 不带`=`号会少复制个'\0'
            {
                _str[i] = _str[i+len];
                ++i;
            }
            // for(size_t i=pos+len; i<=_size; i++)
            // {
            //     _str[i-len] = _str[i];
            // }
            _size -= len ;
        }

        return *this;
    }


    // string& string::operator=(const string& s)
    // {
    //     // if(_capacity < s._capacity)
    //     // {
    //     //     reserve(s._capacity);
    //     // }
    //     // _size = s._size;
    //     // strcpy(_str, s._str);
    //     if (this != &s)
    //     {
    //         delete[] _str;

    //         _str = new char[s._capacity + 1];
    //         strcpy(_str, s._str);
    //         _size = s._size;
    //         _capacity = s._capacity;
    //     }
    //     return *this ;
    // }

    // 现代写法
    // string& string::operator=(const string& s)
    // {
    //     string tmp(s);
    //     this->swap(tmp);
    //     return *this ;
    // }

    // 现代写法2
    string& string::operator=(string tmp)
    {
        swap(tmp);
        return *this ;
    }

    string string::operator+(const string& s) const
    {
        string newstr = *this;
        newstr += s;
        return newstr;
    }


    string& string::operator+=(const string& s)
    {
        if(s._size+_size > _capacity)
        {
            size_t new_capcity = s._size+_size > _capacity*2?(s._size+_size):_capacity*2 ;
            reserve(new_capcity);
        }
        char* pc = s._str;
        while(*pc)
        {
            _str[_size++] = *(pc++);
        }
        _str[_size] = '\0' ;
        return *this;
    }

    bool string::operator>(const string& s) const
    {
        return strcmp(_str, s._str) > 0;
    }

    bool string::operator>=(const string& s) const
    {
        return ((*this)>s) || ((*this) == s);
    }
    
    bool string::operator<(const string& s) const
    {
        return !((*this) >= s);
    }

    bool string::operator<=(const string& s) const
    {
        return !((*this) > s);
    }

    bool string::operator==(const string& s) const
    {
        return strcmp(_str, s._str) == 0;
    }

    bool string::operator!=(const string& s) const
    {
        return !((*this) == s);
    }
};

std::ostream& operator<<(std::ostream& out, const real::string& s)
{
    return out << s.c_str();
}